#pragma once
#include "Sock.hpp"
#include <assert.h>

#define NUM (sizeof(fd_set) * 8) // 数组元素个数
#define FD_NONE -1 // 数组初始化的值，表明没有这个fd

class SelectServer
{
public:
    SelectServer(uint16_t port = 8080)
        :_port(port)
    {
        // 创建套接字
        _listenSock = Sock::Socket();
        
        // bind绑定
        Sock::Bind(_listenSock, _port);

        // 设置监听状态
        Sock::Listen(_listenSock);

        // 对_rdArray数组初始化
        for(int i = 0; i < NUM; ++i)
        {
            _rdArray[i] = FD_NONE; // 每一个都设置成FD_NONE，表明某一位没有文件描述符
        }
        // 规定第一个位为_listenSock，因为_listenSock一直存在
        _rdArray[0] = _listenSock;
    }

    void Start()
    {
        while(1)
        {
            showFds(); // 每次打印一下数组中有效的fd

            fd_set rfds; // 读文件描述符集
            FD_ZERO(&rfds); // 初始化

            // 找出最大的文件描述符
            int maxfd = _listenSock;

            for(int i = 0; i < NUM; ++i)
            {
                if(_rdArray[i] == FD_NONE) continue;
               
                // 找出最大的文件描述符
                if(maxfd < _rdArray[i]) maxfd = _rdArray[i];
                // 有效的文件描述符设置到select中
                FD_SET(_rdArray[i], &rfds);
            }

            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
            // select第一个参数为最大文件描述符 + 1，这里最大的文件描述符就是maxfd
            // 中间只关心读文件描述符集，所以只搞了一个，后面两个都是空
            // 最后一个是timeout，先演示一下nullptr为空，阻塞等待
            
            // timeval tv;
            // tv.tv_sec = 5;
            // tv.tv_usec = 0;
            // int n = select(_listenSock + 1, &rfds, nullptr, nullptr, &tv);
            switch(n)
            {
            case 0:
                LogMessage(DEBUG, _F, _L, "time out");
                break;
            case -1:
                LogMessage(ERROR, _F, _L, "select err, errno::%d, strerror::", errno, strerror(errno));
                break;
            default:
                LogMessage(NORMAL, _F, _L, "fd is ready");
                EventHandler(rfds);
                break;
            }
        }
    }

    void EventHandler(fd_set& rfds)
    {
        for(int i = 0; i < NUM; ++i)
        {
            // 是否有效
            if(_rdArray[i] == FD_NONE) continue;

            // 是否就绪
            if(FD_ISSET(_rdArray[i], &rfds))
            {
                if(i == 0)// 是listenSock
                {
                    Accepter();
                }
                else // 是通信的sock
                {
                    Reader(i);
                }
            }
        }

        // if(FD_ISSET(_listenSock, &rfds))
        // {
        //     // 客户端IP + 端口
        //     std::string clientIP;
        //     uint16_t clientPort;

        //     int sock = Sock::Accept(_listenSock, clientIP, clientPort);
        //     assert(sock >= 0);
        //     LogMessage(NORMAL, _F, _L, "get link -->client[%s:%d]", clientIP.c_str(), clientPort);
            
        //     // 通信过程...
        //     int pos = 1;
        //     for(; pos < NUM; ++pos)
        //     {// 找FD_NONE
        //         if(_rdArray[pos] == FD_NONE) break;
        //     }
        //     if(pos == NUM)
        //     {// 没找到
        //         std::cout << "文件描述符集已满, 无法继续接收连接" << std::endl;
        //         close(sock);
        //         return;
        //     }
        //     else
        //     {// 找到了
        //         std::cout << "new fd::" << sock << std::endl;
        //         _rdArray[pos] = sock;
        //     }
        // }
    }

    void Accepter()
    {
        // 客户端IP + 端口
        std::string clientIP;
        uint16_t clientPort;

        int sock = Sock::Accept(_listenSock, clientIP, clientPort);
        assert(sock >= 0);
        LogMessage(NORMAL, _F, _L, "get link -->client[%s:%d]", clientIP.c_str(), clientPort);
        
        // 通信过程...
        int pos = 1;
        for(; pos < NUM; ++pos)
        {// 找FD_NONE
            if(_rdArray[pos] == FD_NONE) break;
        }
        if(pos == NUM)
        {// 没找到
            std::cout << "文件描述符集已满, 无法继续接收连接" << std::endl;
            close(sock);
            return;
        }
        else
        {// 找到了
            std::cout << "new fd::" << sock << std::endl;
            _rdArray[pos] = sock;
        }
    }

    void Reader(int pos)
    {
        char buff[128] = {0};
        ssize_t res = read(_rdArray[pos], buff, sizeof(buff) - 1);
        if(res > 0)
        {// 读取到数据
            buff[res - 1] = 0;
            printf("get client[%d] message # %s\n", _rdArray[pos], buff);
        }
        else if(res == 0)
        {// 对端关闭连接
            printf("client[%d] closed, me too\n", _rdArray[pos]);
            close(_rdArray[pos]);
            // 记得要把数组中对应位置置为FD_NONE
            _rdArray[pos] = FD_NONE;
        }
        else
        {// read出错
            printf("read err, close client[%d]\n", _rdArray[pos]);
            std::cout << "read err ::" << errno << strerror(errno) << std::endl; 
            close(_rdArray[pos]);
            // 记得要把数组中对应位置置为FD_NONE
            _rdArray[pos] = FD_NONE;
        }
    }

    void showFds()
    {
        std::cout << "fds ::";
        for(auto e : _rdArray)
        {
            if(e == FD_NONE) continue;
            std::cout << e << ' ';
        }

        std::cout << std::endl;
    }

    ~SelectServer()
    {
        if(_listenSock >= 0)
        {
            close(_listenSock);
        }
    }


private:
    uint16_t _port;
    int _listenSock;
    int _rdArray[NUM];
};